﻿using System;
using TradeHelp.Utilities;

namespace TradeHelp.MaterializedObjectViews
{
    /// <summary>
    /// Defines the type of data contained withing the ViewMessage
    /// </summary>
    public enum ViewAction
    {
        Add, Update, Remove
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public struct ViewMessage<T>
    {
        private ViewMessage(ViewAction action, T data, T prevData)
        {
            Invariant.CheckIsNull(data, "data");

            Action = action;
            Data = data;
            PrevData = prevData;
        }

        /// <summary>
        /// Provides a convert operation for a message
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="converter"></param>
        /// <returns></returns>
        public ViewMessage<TResult> Convert<TResult>(Func<T, TResult> converter)
        {
            Invariant.CheckIsNull(converter, "converter");
            if (Action == ViewAction.Add)
            {
                return ViewMessage<TResult>.CreateAdd(converter(Data));
            }
            if (Action == ViewAction.Remove)
            {
                return ViewMessage<TResult>.CreateRemove(converter(Data));
            }
            if (Action == ViewAction.Update)
            {
                return ViewMessage<TResult>.CreateUpdate(converter(Data), converter(PrevData));
            }
            throw new Exception();
        }

        /// <summary>
        /// Factory method for add message
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static ViewMessage<T> CreateAdd(T data)
        {
            return new ViewMessage<T>(ViewAction.Add, data, default(T));
        }

        /// <summary>
        /// Factory method for update message
        /// </summary>
        /// <param name="data"></param>
        /// <param name="prevData"></param>
        /// <returns></returns>
        public static ViewMessage<T> CreateUpdate(T data, T prevData)
        {
            return new ViewMessage<T>(ViewAction.Update, data, prevData);
        }

        /// <summary>
        /// Factory method for remove message
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static ViewMessage<T> CreateRemove(T data)
        {
            return new ViewMessage<T>(ViewAction.Remove, data, default(T));
        }

        /// <summary>
        /// 
        /// </summary>
        public readonly ViewAction Action;

        /// <summary>
        /// Data payload of the view message.
        /// </summary>
        public readonly T Data;

        /// <summary>
        /// Previous data only defined for view message updates.
        /// </summary>
        public readonly T PrevData;

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("{0}|{1}|{2}", Action, PrevData, Data);
        }
    }
}